// 子线程函数放这里
#include "factory.h"

void cleanup(void *p)
{
    pthread_mutex_t *pmutex = (pthread_mutex_t *)p;
    pthread_mutex_unlock(pmutex); // 解锁
}

// 子线程流程
void *threadFunc(void *p)
{
    factory_t *pFactory = (factory_t *)p;
    taskQueue_t *pQue = &pFactory->taskQueue;
    task_t *pnew;
    int taskFlag; // 是否拿到任务
    while (1)
    {
        pthread_mutex_lock(&pQue->mutex);// 加锁
        pthread_cleanup_push(cleanup, &pQue->mutex);// 清理函数
        if (!pQue->queueSize)// 判断队列为空
        {
            pthread_cond_wait(&pFactory->cond, &pQue->mutex); // 睡觉
        }
        if (pFactory->exitFlag)
        {
            printf("子线程退出\n");
            pthread_exit(NULL);
        }
        // 出队
        taskFlag = taskDequeue(pQue, &pnew);
        pthread_cleanup_pop(1); // 通过pop去解锁
        if (!taskFlag)          // 拿到任务后
        {
            printf("开始处理客户端的各种请求\n");
            client_handle(pnew);
            mysql_close(pnew->conn);//关闭连接
            close(pnew->new_fd);
            free(pnew);
        }
        if (pFactory->exitFlag)
        {
            printf("子线程退出\n");
            pthread_exit(NULL);
        }
    }
}

void client_handle(task_t *pnew)
{
    int control_code;
    int new_fd = pnew->new_fd;
    int ret;
    char client_data[2000];

    while (1)
    {
        bzero(client_data,sizeof(client_data));
        ret=recv_protocal(new_fd, &control_code, client_data);
        printf("control_code %d\n",control_code);
        if(-1==ret)
        {
            printf("客户端断开\n");
            break;//客户端断开
        }
        switch (control_code)
        {
        case LS:
            do_ls(pnew);
            break;
        case CD:
            do_cd(pnew,client_data);
            break;
        case PWD:
            do_pwd(pnew);
            break;
        case MKDIR:
            do_mkdir(pnew,pnew->conn,client_data);
            break;
        case RM:
            do_rm(pnew,client_data);
            break;
        case GETS:
            do_gets(pnew,client_data);
            break;
        case PUTS:
            do_puts(pnew,client_data);
            break;
        default:
            break;
        }
    }
}

void do_ls(task_t *pnew)
{
    send_file_info(pnew);
}
// cd  ..
// cd 目录名 ;path参数存储的是..或者目录名
void do_cd(task_t *pnew,char *path)
{
    //如果是..
    if(!strcmp(path,".."))
    {
        if(0!=pnew->path_id)//不是根，是根，什么都不做
        {
            //通过pnew->path_id得到pre_id
            pnew->path_id=get_pre_id(pnew->conn,pnew->path_id);
            //pnew->path
            modify_path_slash(pnew->path);
            LOG(pnew->path);
        }
        send_protocal(pnew->new_fd,SUCCESS,pnew->path,strlen(pnew->path));
    }else
    {
        int path_id=check_cd_dir_isexist(pnew->conn,pnew->user_id,pnew->path_id,path);
        if(path_id)
        {
            //改变path，和path_id;
            char new_path[2000]={0};
            sprintf(new_path,"%s%s/",pnew->path,path);
            strcpy(pnew->path,new_path);
            pnew->path_id=path_id;
            send_protocal(pnew->new_fd,SUCCESS,pnew->path,strlen(pnew->path));
        }else{
            send_protocal(pnew->new_fd,FAILED,NULL,0);//切换失败
        }
    }
}
void do_pwd(task_t *pnew)
{
    send_protocal(pnew->new_fd,SUCCESS,pnew->path,strlen(pnew->path));
}

void do_mkdir(task_t *pnew,MYSQL* conn,char* dir_name)
{
    int dir_isexist;
    dir_isexist=check_dir_isexist(conn,pnew->user_id,pnew->path_id,dir_name);
    printf("dir_isexist %d\n",dir_isexist);
    if(dir_isexist)//存在同名文件，不能创建
    {
        send_protocal(pnew->new_fd,FAILED,NULL,0);
    }else{
        creat_dir(conn,pnew->user_id,pnew->path_id,dir_name);
        send_protocal(pnew->new_fd,SUCCESS,NULL,0);
    }
}
void do_rm(task_t *pnew,char* rm_file_name)
{
    int rm_flag;
    rm_flag=rm_file_emptydir(pnew,rm_file_name);
    if(rm_flag)
    {
        send_protocal(pnew->new_fd,SUCCESS,NULL,0);
    }else{
        send_protocal(pnew->new_fd,FAILED,NULL,0);
    }
}
void do_gets(task_t *pnew,char *file_name_and_len)
{
    off_t seek_pos,file_size;
    seek_pos=get_file_name_pos(file_name_and_len);
    char md5_str[50]={0};
    //获得文件md5和大小
    get_md5_and_file_size(pnew,md5_str,&file_size,file_name_and_len);
    //发送文件,md5值就是文件名,file_size-seek_pos就是实际要发送的大小
    transFile(pnew->new_fd,md5_str,seek_pos,file_size-seek_pos);
}

void do_puts(task_t *pnew,char* file_name)
{
    char md5_str[50]={0};
    int recvLen;
    recvn(pnew->new_fd,&recvLen,4);//接火车车厢
    recvn(pnew->new_fd,md5_str,recvLen);//接recvLen长度的数据
    uint64_t second_transfer;//秒传标志
    second_transfer=check_file_md5_exist(pnew,md5_str);
    if(second_transfer)//秒传
    {
        //file_system插入一条记录，给客户端回复上传成功
        creat_file(pnew->conn,pnew->user_id,pnew->path_id,file_name,md5_str);
        send_protocal(pnew->new_fd,SUCCESS,NULL,0);
    }else{
        send_protocal(pnew->new_fd,FAILED,NULL,0);//发送秒传失败
        off_t file_size;
        file_size=recvFile(pnew->new_fd,md5_str);
        //在file_md5sum新增一条记录
        creat_file_md5(pnew->conn,md5_str,file_size);
        //file_system插入一条记录，给客户端回复上传成功
        creat_file(pnew->conn,pnew->user_id,pnew->path_id,file_name,md5_str);
        printf("上传成功\n");
    }
}